package com.duojuhe.redis.redisson.impl;

import com.duojuhe.redis.redisson.DistributedLocker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class DistributedLockerImpl implements DistributedLocker {
    private RedissonClient redissonClient;

    public DistributedLockerImpl(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    //lock(), 拿不到lock就不罢休，不然线程就一直block
    @Override
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    //leaseTime为加锁时间，单位为秒
    @Override
    public RLock lock(String lockKey, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.SECONDS);
        return lock;
    }

    //timeout为加锁时间，时间单位由unit确定
    @Override
    public RLock lock(String lockKey, long timeout,TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    //公平锁（Fair Lock）
    //lock(), 拿不到lock就不罢休，不然线程就一直block
    @Override
    public RLock fairLock(String lockKey) {
        RLock lock = redissonClient.getFairLock(lockKey);
        lock.lock();
        return lock;
    }

    //timeout为加锁时间，单位为秒
    @Override
    public RLock fairLock(String lockKey, long timeout) {
        RLock lock = redissonClient.getFairLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

    //timeout为加锁时间，时间单位由unit确定
    @Override
    public RLock fairLock(String lockKey, long timeout,TimeUnit unit) {
        RLock lock = redissonClient.getFairLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    //tryLock()，马上返回，拿到lock就返回true，不然返回false。
    //带时间限制的tryLock()，拿不到lock，就等一段时间，超时返回false.
    @Override
    public boolean tryLock(String lockKey, long waitTime, long leaseTime,TimeUnit unit) {
        if (StringUtils.isBlank(lockKey)){
            log.error("传递lockKey字符串为空，不能获得锁");
            return false;
        }
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }

    //tryLock()，马上返回，拿到lock就返回true，不然返回false。【单位秒】
    //带时间限制的tryLock()，拿不到lock，就等一段时间，超时返回false.
    @Override
    public boolean tryLock(String lockKey, long waitTime, long leaseTime) {
        if (StringUtils.isBlank(lockKey)){
            log.error("传递lockKey字符串为空，不能获得锁");
            return false;
        }
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }

    //tryLock()，马上返回，拿到lock就返回true，不然返回false。【至少一秒】
    //带时间限制的tryLock()，等待1秒钟，超时返回false.
    @Override
    public boolean tryLock(String lockKey, long leaseTime) {
        if (StringUtils.isBlank(lockKey)){
            log.error("传递lockKey字符串为空，不能获得锁");
            return false;
        }
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (leaseTime<1){
                leaseTime = 1L;
            }
            return lock.tryLock(1L, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }


    //tryLock()，马上返回，拿到lock就返回true，不然返回false。【单位秒】
    //带时间限制的tryLock()，拿不到lock，就等一段时间，超时返回false.
    @Override
    public boolean fairTryLock(String lockKey, long waitTime) {
        if (StringUtils.isBlank(lockKey)){
            log.error("传递lockKey字符串为空，不能获得锁");
            return false;
        }
        RLock lock = redissonClient.getFairLock(lockKey);
        try {
            return lock.tryLock(waitTime,TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }

    //fairTryLock()，马上返回，拿到lock就返回true，不然返回false。【公平锁】
    //带时间限制的tryLock()，拿不到lock，返回false.
    @Override
    public boolean fairTryLock(String lockKey) {
        if (StringUtils.isBlank(lockKey)){
            log.error("传递lockKey字符串为空，不能获得锁");
            return false;
        }
        RLock lock = redissonClient.getFairLock(lockKey);
        try {
            return lock.tryLock();
        } catch (Exception e) {
            return false;
        }
    }

    //释放指定key锁
    @Override
    public void unlock(String lockKey) {
        if (StringUtils.isBlank(lockKey)){
            log.error("传递lockKey字符串为空，不能进行解锁");
            return;
        }
        RLock lock = redissonClient.getLock(lockKey);
        if(lock.isLocked()){
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }

    //释放锁
    @Override
    public void unlock(RLock lock) {
        if (lock!=null){
            if(lock.isLocked()){
                if(lock.isHeldByCurrentThread()){
                    lock.unlock();
                }
            }
        }
    }
}